/*
 * Example drawn from cppreference 
 * https://en.cppreference.com/w/cpp/utility/functional/invoke
 * 
 * */
#include <cxxomfort/functional.hpp> // functional
#include <iostream>

template <typename T>
T sum2 (T a, T b) { return a+b; }

struct Foo {
    Foo(int num) : num_(num) {}
    void print_add(int i) const { std::cout << num_+i << '\n'; }
    int num_;
};
 
void print_num(int i)
{
    std::cout << i << '\n';
}
 
struct PrintNum {
    void operator()(int i) const
    {
        std::cout << i << '\n';
    }
};
 
int main() {
	using namespace std;
	cxxomfort::output_info(stdout);
	cout<< endl;

	cout<< "std::invoke support / implements: "
		<< CXXO_COMPILER_SUPPORT_invoke<< " / "
		<< CXXOMFORT_IMPLEMENTS_invoke<< endl;

	cout<< "std::invoke_r support / implements: "
		<< CXXO_COMPILER_SUPPORT_invoke_r<< " / "
		<< CXXOMFORT_IMPLEMENTS_invoke_r<< endl;

#if (defined(__cpp_lib_invoke))
	cout<< "invoke: available."<< endl;

    // invoke a free function
    invoke(print_num, -9);
 
    // invoke a lambda
#if (CXXO_COMPILER_SUPPORT_lambda_expressions)
    invoke([]() { print_num(42); });
#else
	cout<< "lambda test: not available"<< endl;
#endif

    // invoke a member function
    const Foo foo(314159);
    invoke(&Foo::print_add, foo, 1);
 
    // invoke (access) a data member
    cout << "num_: " << invoke(&Foo::num_, foo) << '\n';
 
    // invoke a function object
    invoke(PrintNum(), 18);
#else
	std::cout<< "invoke: not available."<< std::endl;
#endif
 
#if (defined(__cpp_lib_invoke_r))
	cout<< "invoke_r: available."<< endl;

#if (CXXOMFORT_CXX_STD>=2011)
    auto add = [](int x, int y) { return x + y; };
#else
	plus<void> add;
#endif
    float ret = std::invoke_r<float>(add, 11, 22);
    enum R { retval = std::is_same<decltype(ret), float>::value };
    static_assert(retval, "retval");
    std::cout << ret << '\n';
    std::invoke_r<void>(print_num, 44);
#else
	std::cout<< "invoke_r: not available."<< std::endl;
#endif

}

